<script setup lang="ts">
import { computed, useAttrs } from 'vue';

/** 由于 n-select 组件不支持 value 为布尔值，所以需要自定义 */
/** 方案是将布尔值 value 转换为字符串，然后在下拉框中显示 options 中对应的 label，用户选择后再将其转换回布尔值 */

defineOptions({
  name: 'BooleanSelect',
  inheritAttrs: false
});

interface Props {
  options: any[];
  clearable?: boolean;
  placeholder?: string;
}

const { options, placeholder = '', clearable = true } = defineProps<Props>();

const model = defineModel<boolean | null>('value', {
  default: null
});

const selectModel = computed({
  get: () => {
    if (model.value === null) return null;
    return model.value === true ? 'true' : 'false';
  },
  set: val => {
    if (val === null) {
      model.value = val;
    } else {
      model.value = val === 'true';
    }
  }
});

const selectOptions = computed(() => {
  return options.map(item => ({
    label: item.label,
    value: item.value.toString()
  }));
});

const attrs = useAttrs() as Record<string, any>;

/** 提取事件 */
const listeners = computed<Record<string, (...args: unknown[]) => void>>(() => {
  return Object.keys(attrs).reduce<Record<string, (...args: unknown[]) => void>>((acc, key) => {
    if (key.startsWith('on') && typeof attrs[key] === 'function') {
      acc[key] = attrs[key] as (...args: unknown[]) => void;
    }
    return acc;
  }, {});
});
</script>

<template>
  <NSelect
    v-bind="attrs"
    v-model:value="selectModel"
    :options="selectOptions"
    :clearable="clearable"
    :placeholder="placeholder"
    v-on="listeners"
  />
</template>

<style lang="scss" scoped></style>
